`timescale 1ns/1ps
module generic_asyn_fifo(
					//output
					dout,
					paf,  
					ff, 
					ef,
					overmark,
						//input
						wr_clk, 
						rd_clk, 
						wr_rst,
						rd_rst,
						wr_clr,
						rd_clr,
						din, 
						wen,
						ren,
						pm
                    	 );
  parameter dw=8;
  parameter aw=10;
  parameter n=11;

  input		      	wr_clk, rd_clk;
  input		      	wr_rst, rd_rst;   //low active
  input		       	wr_clr, rd_clr;   //high active 
  input	[dw-1:0]	din;
  input			      wen;         //low active
  input			      ren;         //low active
  input [2:0]     pm;              //3'b001 means 1/8 level,wr_clock domain
  
  output [dw-1:0]	dout;
  output          paf;             //high active
  output		    	ff;        //low active
  output			    ef;        //low active
  output          overmark;        //low active
  
//////////////////////////////////////////////////////////////////
//
//	Local Wires
//
   
  wire  [aw:0]		wp_bin;    
  wire  [aw:0]		wp_gray;
  wire  [aw:0]		rp_bin;
  wire  [aw:0]		rp_gray;

  wire  [aw:0]		wp_s;
  wire  [aw:0]		rp_s;
  wire            ren_c;
  wire            wen_c;
  
  
  assign  ren_c = ren|(!ef);
  assign  wen_c = wen|(!ff);
   
  
////////////////////////////////////////////////////////////////////
//
//	Memory Block
//
generate 
	if(dw==8)
	RFTP1024X8M2 u0(
	    .CLKA(rd_clk),
	    .CENA(ren_c),  
	    .ADA(rp_bin[aw-1:0]),
	    .DAOUT(dout),
	    .CLKB(wr_clk),
	    .CENB(wen_c),
	    .ADB(wp_bin[aw-1:0]),
	    .DBIN(din)
		);
	else if(dw==24)
	RFTP1024X24M2 u0(
	    .CLKA(rd_clk),
	    .CENA(ren_c),  
	    .ADA(rp_bin[aw-1:0]),
	    .DAOUT(dout),
	    .CLKB(wr_clk),
	    .CENB(wen_c),
	    .ADB(wp_bin[aw-1:0]),
	    .DBIN(din)
		);
	else if(dw==48)
	begin
	RFTP256X48M2 u0(
	    .CLKA(rd_clk),
	    .CENA(ren_c),  
	    .ADA(rp_bin[aw-1:0]),
	    .DAOUT(dout),
	    .CLKB(wr_clk),
	    .CENB(wen_c),
	    .ADB(wp_bin[aw-1:0]),
	    .DBIN(din)
		);
	end
endgenerate

////////////////////////////////////////////////////////////////////
//
//	Synchronizer
//
sync_r2w #(aw) sync_r2w(      
				//output
				.rp_s(rp_s),
				//input           
				.wr_clk(wr_clk),
				.wr_rst(wr_rst),
				.wr_clr(wr_clr),
				.rp_gray(rp_gray)
                 );
                 
sync_w2r #(aw) sync_w2r(      
				//output
				.wp_s(wp_s),
				//input           
				.rd_clk(rd_clk),
				.rd_rst(rd_rst),
				.rd_clr(rd_clr),
				.wp_gray(wp_gray)
                 );


rptr_empty #(aw) rptr_empty(
				//output
				.ef(ef),
				.rp_bin(rp_bin),
				.rp_gray(rp_gray),
                //input
				.rd_clk(rd_clk), 
				.rd_rst(rd_rst),
				.rd_clr(rd_clr),
				.ren(ren_c),
				.wp_s(wp_s)
                 );    
                    	 
wptr_full #(aw) wptr_full(
				//output
				.ff(ff),
				.wp_bin(wp_bin),
				.wp_gray(wp_gray),
				//input
				.wr_clk(wr_clk),
				.wr_rst(wr_rst),
				.wr_clr(wr_clr),
				.wen(wen_c),
				.rp_s(rp_s)
                 );
                 
 rptr_overmark #(aw) rptr_overmark(
				//output
				.overmark(overmark),
				//input
				.rd_clk(rd_clk),
				.rd_rst(rd_rst),
				.rd_clr(rd_clr),
				.rp_bin(rp_bin),
				.wp_s(wp_s),
				.pm(pm)
                 );
                 
 wptr_paf  #(aw,n) wptr_paf(
				//output
				.paf(paf),
				//input
				.wr_clk(wr_clk),
				.wr_rst(wr_rst),
				.wr_clr(wr_clr),
				.wp_bin(wp_bin),
				.rp_s(rp_s)
                 );                 
                 
                                
endmodule